﻿using System;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;


namespace PubSubSubscriber
{
    public class Subscriber
    {
        private Socket _client;
        private EndPoint _remoteEndPoint;
        private byte[] _data;
        //private int _recv;
        private Boolean _isReceivingStarted = false;

        public EventHandler<MessageChangedArgs> messageChanged;

        private bool stopReceive = false;

        private IPAddress _serverIPAddress;
        private int _serverPort;

        public IPAddress ServerIPAddress
        {
            get { return _serverIPAddress; }
            set { _serverIPAddress = value; }
        }

        public int ServerPort
        {
            get { return _serverPort; }
            set { _serverPort = value; }
        }
        
        public Subscriber(string serverIP, int serverPort)
        {
            //string serverIP = "127.0.0.1";
            _serverIPAddress = IPAddress.Parse(serverIP);
            //int serverPort = 10009;
            _serverPort = serverPort;

            _client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            _remoteEndPoint = new IPEndPoint(_serverIPAddress, _serverPort);
        }

        //private void ReceiveDataFromServer()
        //{
        //    EndPoint publisherEndPoint = _client.LocalEndPoint;
        //    while (true)
        //    {
        //        _recv = _client.ReceiveFrom(_data, ref publisherEndPoint);
        //        string msg = Encoding.ASCII.GetString(_data, 0, _recv) + "," + publisherEndPoint.ToString();
        //        if (messageChanged != null)
        //        {
        //            messageChanged(this, new MessageChangedArgs(msg));
        //        }
        //    }
        //}

        public void Subscribe(string topicName)
        {
            try
            {
                string Command = "Subscribe";

                string message = Command + "," + topicName.ToString();
                _client.SendTo(Encoding.ASCII.GetBytes(message), _remoteEndPoint);

                if (_isReceivingStarted == false)
                {
                    _isReceivingStarted = true;
                    //_data = new byte[1024];
                    _data = new byte[64000];
                    //Thread thread1 = new Thread(new ThreadStart(ReceiveDataFromServer));
                    //thread1.IsBackground = true;
                    //thread1.Start();

                    //EndPoint publisherEndPoint = _client.LocalEndPoint;

                    // Begin receiving the data from the remote device.
                    _client.BeginReceiveFrom(_data, 0, _data.Length, SocketFlags.None, ref _remoteEndPoint, new AsyncCallback(ReceiveData), _client);
                    Console.WriteLine("Subscribe done");
                }
            }
            catch (Exception e)            
            {
                Console.WriteLine(e.ToString());
            }
        }

        private void ReceiveData(IAsyncResult iar)
        {
            try
            {
                //// Retrieve the state object and the client socket 
                //// from the asynchronous state object.
                //StringBuilder sb = (StringBuilder)ar.AsyncState;
                ////Socket client = state.workSocket;
                //// Read data from the remote device.
                //int bytesRead = _client.EndReceive(ar);
                //if (bytesRead > 0)
                //{
                //    // There might be more data, so store the data received so far.
                //    sb.Append(Encoding.ASCII.GetString(_data, 0, bytesRead));
                //    //  Get the rest of the data.
                //    _client.BeginReceive(_data, 0, 1024, 0, new AsyncCallback(ReceiveCallback), sb);
                //}
                //else
                //{
                //    // All the data has arrived; put it in response.
                //    if (sb.Length > 1)
                //    {
                //        received = sb.ToString();
                //        Console.WriteLine(received);
                //    }
                //    // Signal that all bytes have been received.
                //    //receiveDone.Set();
                //                 }

               Socket remote = (Socket)iar.AsyncState;
               EndPoint publisherEndPoint = remote.LocalEndPoint;
               int recv = remote.EndReceiveFrom(iar, ref publisherEndPoint);
               string stringData = Encoding.ASCII.GetString(_data, 0, recv);
               Console.WriteLine(stringData);

               if (messageChanged != null)
               {
                   messageChanged(this, new MessageChangedArgs(stringData));
               }

               if (!stopReceive)
               {
                   // Begin receiving the data from the remote device.
                   remote.BeginReceiveFrom(_data, 0, _data.Length, SocketFlags.None, ref publisherEndPoint, new AsyncCallback(ReceiveData), remote);
               }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

        public void Unsubscribe(string topicName)
        {
            string command = "UnSubscribe";
            string message = command + "," + topicName.ToString();
            _client.SendTo(Encoding.ASCII.GetBytes(message), _remoteEndPoint);
        }

        //public void Subscribe(Topic.WII topicName)
        //{
        //    string Command = "Subscribe";

        //    string message = Command + ",WII|" + topicName.ToString();
        //    _client.SendTo(Encoding.ASCII.GetBytes(message), _remoteEndPoint);

        //    if (_isReceivingStarted == false)
        //    {
        //        _isReceivingStarted = true;
        //        _data = new byte[1024];
        //        Thread thread1 = new Thread(new ThreadStart(ReceiveDataFromServer));
        //        thread1.IsBackground = true;
        //        thread1.Start();
        //    }

        //}

        //public void Unsubscribe(Topic.WII topicName)
        //{
        //    string command = "UnSubscribe";

        //    string message = command + ",WII|" + topicName.ToString();
        //    _client.SendTo(Encoding.ASCII.GetBytes(message), _remoteEndPoint);
        //}

        public void Shutdown()
        {
            stopReceive = true;
            _client.Disconnect(true);
            _client.Close();
            _client = null;
        }
    }

    public class MessageChangedArgs : EventArgs
    {
        public string message;
        public MessageChangedArgs(string msg)
        {
            message = msg;
        }
    }
    //public static class Topic
    //{
    //    public enum WII
    //    {
    //        A,
    //        B,
    //        Up,
    //        Down,
    //        Left,
    //        Right,
    //        Minus,
    //        Plus,
    //        Home,
    //        One,
    //        Two,
    //        X,
    //        Y,
    //        Z,
    //        ir0X,
    //        ir0Y,
    //        ir1X,
    //        ir1Y,
    //        ir2X,
    //        ir2Y,
    //        ir3X,
    //        ir3Y,
    //        irRaw0X,
    //        irRaw0Y,
    //        irRaw1X,
    //        irRaw1Y,
    //        irRaw2X,
    //        irRaw2Y,
    //        irRaw3X,
    //        irRaw3Y,
    //        ir0Size,
    //        ir1Size,
    //        ir2Size,
    //        ir3Size,
    //        ir0Found,
    //        ir1Found,
    //        ir2Found,
    //        ir3Found,
    //        LED1,
    //        LED2,
    //        LED3,
    //        LED4,
    //        Yaw,
    //        Pitch,
    //        Roll,
    //        ExtensionType,
    //        ExtensionInserted,
    //        Rumble,
    //        Battery,
    //        NunC,
    //        NunZ,
    //        NunXAcc,
    //        NunYAcc,
    //        NunZAcc,
    //        NunXJoystick,
    //        NunYJoystick,
    //        NunYaw,
    //        NunPitch,
    //        NunRoll
    //    }
    //    public enum ARDUINO
    //    {
    //        Light,
    //        Temperature,
    //        Servo
    //    }

    //    //public static class Topic
    //    //{
    //    //    public enum WII
    //    //    {
    //    //        A = "WII|A",
    //    //        B = "WII|B",
    //    //        Up = "WII|Up",
    //    //        Down = "WII|Down",
    //    //        Left = "WII|Left",
    //    //        Right = "WII|Right",
    //    //        Minus = "WII|Minus",
    //    //        Plus = "WII|Plus",
    //    //        Home = "WII|Home",
    //    //        One = "WII|One",
    //    //        Two = "WII|Two",
    //    //        X = "WII|X",
    //    //        Y = "WII|Y",
    //    //        Z = "WII|Z",
    //    //        ir0X = "WII|ir0X",
    //    //        ir0Y = "WII|ir0Y",
    //    //        ir1X = "WII|ir1X",
    //    //        ir1Y = "WII|ir1Y",
    //    //        ir2X = "WII|ir2X",
    //    //        ir2Y = "WII|ir2Y",
    //    //        ir3X = "WII|ir3X",
    //    //        ir3Y = "WII|ir3Y",
    //    //        irRaw0X = "WII|irRaw0X",
    //    //        irRaw0Y = "WII|irRaw0Y",
    //    //        irRaw1X = "WII|irRaw1X",
    //    //        irRaw1Y = "WII|irRaw1Y",
    //    //        irRaw2X = "WII|irRaw2X",
    //    //        irRaw2Y = "WII|irRaw2Y",
    //    //        irRaw3X = "WII|irRaw3X",
    //    //        irRaw3Y = "WII|irRaw3Y",
    //    //        ir0Size = "WII|ir0Size",
    //    //        ir1Size = "WII|ir1Size",
    //    //        ir2Size = "WII|ir2Size",
    //    //        ir3Size = "WII|ir3Size",
    //    //        ir0Found = "WII|ir0Found",
    //    //        ir1Found = "WII|ir1Found",
    //    //        ir2Found = "WII|ir2Found",
    //    //        ir3Found = "WII|ir3Found",
    //    //        LED1 = "WII|LED1",
    //    //        LED2 = "WII|LED2",
    //    //        LED3 = "WII|LED3",
    //    //        LED4 = "WII|LED4",
    //    //        Yaw = "WII|Yaw",
    //    //        Pitch = "WII|Pitch",
    //    //        Roll = "WII|Roll",
    //    //        ExtensionType = "WII|ExtensionType",
    //    //        ExtensionInserted = "WII|ExtensionInserted",
    //    //        Rumble = "WII|Rumble",
    //    //        Battery = "WII|Battery",
    //    //        NunC = "WII|NunC",
    //    //        NunZ = "WII|NunZ",
    //    //        NunXAcc = "WII|NunXAcc",
    //    //        NunYAcc = "WII|NunYAcc",
    //    //        NunZAcc = "WII|NunZAcc",
    //    //        NunXJoystick = "WII|NunXJoystick",
    //    //        NunYJoystick = "WII|NunYJoystick",
    //    //        NunYaw = "WII|NunYaw",
    //    //        NunPitch = "WII|NunPitch",
    //    //        NunRoll = "WII|NunRoll"
    //    //    }
    //    //    public enum ARDUINO
    //    //    {
    //    //        Light = "AR|Light",
    //    //        Temperature = "AR|Temp",
    //    //        Servo = "AR|Servo"
    //    //    }
    //    //}
    //}

}
